/*
基于 Send 和 Sync 的线程安全
*/

/*

// Rc源码片段
impl<T: ?Sized> !marker::Send for Rc<T> {}
impl<T: ?Sized> !marker::Sync for Rc<T> {}

// Arc源码片段
unsafe impl<T: ?Sized + Sync + Send> Send for Arc<T> {}
unsafe impl<T: ?Sized + Sync + Send> Sync for Arc<T> {}
    !代表移除特征的相应实现，上面代码中Rc<T>的Send和Sync特征被特地移除了实现，而Arc<T>则相反，
    实现了Sync + Send:Send和Sync是在线程间安全使用一个值的关键。


Send 和 Sync
Send和Sync是 Rust 安全并发的重中之重，但是实际上它们只是标记特征(marker trait，该特征未定义任何行为，因此非常适合用于标记), 来看看它们的作用：
    实现Send的类型可以在线程间安全的传递其所有权
    实现Sync的类型可以在线程间安全的共享(通过引用)

潜在的依赖：一个类型要在线程间安全的共享的前提是，指向它的引用必须能在线程间传递。
    因为如果引用都不能被传递，我们就无法在多个线程间使用引用去访问同一个数据了
    若类型 T 的引用&T是Send，则T是Sync
    若类型 T 是Sync，则T的引用&T是Send；反之不一定。Mutex就符合上面的“反之”

    当且仅当 &T -> Send ==> T -> Sync 的


    unsafe impl<T: ?Sized + Send + Sync> Sync for RwLock<T> {}
        RwLock可以在线程间安全的共享->实现了Sync
        RwLock可以并发的读，说明其中的值T必定也可以在线程间共享，T->实现Sync

    unsafe impl<T: ?Sized + Send> Sync for Mutex<T> {}
        Mutex<T>中的T并没有Sync特征约束


*/
/*

实现Send和Sync的类型
在 Rust 中，几乎所有类型都默认实现了Send和Sync，而且由于这两个特征都是可自动派生的特征(通过derive派生)
    意味着一个复合类型(例如结构体), :它内部的所有成员 ->都实现了Send或者Sync -> 它就自动实现了Send或Sync

    裸指针两者都没实现，因为它本身就没有任何安全保证
    UnsafeCell不是Sync，因此Cell和RefCell也不是
    Rc两者都没实现(因为内部的引用计数器不是线程安全的)

手动实现 Send 和 Sync 是不安全的，通常并不需要手动实现 Send 和 Sync trait，实现者需要使用unsafe小心维护并发安全保证。
*/
#[cfg(test)]
mod send {
    use std::sync::{Arc, Mutex};
    use std::thread::{self};

    #[derive(Debug)]
    struct MyBox(*mut u8);

    unsafe impl Send for MyBox {}

    #[test]
    fn raw_pointer_send() {
        // let p = 5 as *mut u8;  // 没有实现 send
        let p = MyBox(5 as *mut u8);
        let t = thread::spawn(move || {
            println!("{:?}", p);
        });

        t.join().unwrap();
    }

    // 为裸指针实现Sync
    #[derive(Debug)]
    struct MyBoxConst(*const u8);
    unsafe impl Send for MyBoxConst {}
    unsafe impl Sync for MyBoxConst {}

    // 为裸指针实现Sync //配合Arc去使用
    #[test]
    fn raw_pointer_sync() {
        let b = &MyBoxConst(5 as *const u8);
        let v = Arc::new(Mutex::new(b));

        // 访问的引用实际上还是对主线程中的数据的借用，转移进来的仅仅是外层的智能指针引用

        let t = thread::spawn(move || {
            let _v1 = v.lock().unwrap();
        });

        t.join().unwrap();
    }
}
/*


通过上面的两个裸指针的例子，我们了解了如何实现Send和Sync，以及如何只实现Send而不实现Sync，简单总结下：

    实现Send的类型可以在线程间安全的传递其所有权, 实现Sync的类型可以在线程间安全的共享(通过引用)
    绝大部分类型都实现了Send和Sync，常见的未实现的有：裸指针、Cell、RefCell、Rc 等
    可以为自定义类型实现Send和Sync，但是需要unsafe代码块
    可以为部分 Rust 中的类型实现Send、Sync，但是需要使用newtype，例如文中的裸指针例子

*/
